home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Contrib / IDE mods / Printing / PyEdit.py next >
Encoding:
Python Source  |  2000-06-23  |  34.7 KB  |  1,259 lines

  1. """A (less & less) simple Python editor"""
  2.  
  3. import W
  4. import Wtraceback
  5. from Wkeys import *
  6.  
  7. import macfs
  8. import MacOS
  9. import Win
  10. import Res
  11. import Evt
  12. import os
  13. import imp
  14. import sys
  15. import string
  16. import marshal
  17. import regex
  18.  
  19. _scriptuntitledcounter = 1
  20. _wordchars = string.letters + string.digits + "_"
  21.  
  22.  
  23. class Editor(W.Window):
  24.     
  25.     def __init__(self, path = "", title = ""):
  26.         defaultfontsettings, defaulttabsettings, defaultwindowsize = geteditorprefs()
  27.         global _scriptuntitledcounter
  28.         if not path:
  29.             if title:
  30.                 self.title = title
  31.             else:
  32.                 self.title = "Untitled Script " + `_scriptuntitledcounter`
  33.                 _scriptuntitledcounter = _scriptuntitledcounter + 1
  34.             text = ""
  35.             self._creator = W._signature
  36.         elif os.path.exists(path):
  37.             path = resolvealiases(path)
  38.             dir, name = os.path.split(path)
  39.             self.title = name
  40.             f = open(path, "rb")
  41.             text = f.read()
  42.             f.close()
  43.             fss = macfs.FSSpec(path)
  44.             self._creator, filetype = fss.GetCreatorType()
  45.         else:
  46.             raise IOError, "file '%s' does not exist" % path
  47.         self.path = path
  48.         
  49.         if '\n' in text:
  50.             import EasyDialogs
  51.             if string.find(text, '\r\n') >= 0:
  52.                 sourceOS = 'DOS'
  53.                 searchString = '\r\n'
  54.             else:
  55.                 sourceOS = 'UNIX'
  56.                 searchString = '\n'
  57.             change = EasyDialogs.AskYesNoCancel('“%s” contains %s-style line feeds. Change them to MacOS carriage returns?' % (self.title, sourceOS), 1)
  58.             # bug: Cancel is treated as No
  59.             if change > 0:
  60.                 text = string.replace(text, searchString, '\r')
  61.         else:
  62.             change = 0
  63.         
  64.         self.settings = {}
  65.         if self.path:
  66.             self.readwindowsettings()
  67.         if self.settings.has_key("windowbounds"):
  68.             bounds = self.settings["windowbounds"]
  69.         else:
  70.             bounds = defaultwindowsize
  71.         if self.settings.has_key("fontsettings"):
  72.             self.fontsettings = self.settings["fontsettings"]
  73.         else:
  74.             self.fontsettings = defaultfontsettings
  75.         if self.settings.has_key("tabsize"):
  76.             try:
  77.                 self.tabsettings = (tabsize, tabmode) = self.settings["tabsize"]
  78.             except:
  79.                 self.tabsettings = defaulttabsettings
  80.         else:
  81.             self.tabsettings = defaulttabsettings
  82.         
  83.         W.Window.__init__(self, bounds, self.title, minsize = (330, 120), tabbable = 0)
  84.         self.setupwidgets(text)
  85.         if change > 0:
  86.                 self.editgroup.editor.changed = 1
  87.         
  88.         if self.settings.has_key("selection"):
  89.             selstart, selend = self.settings["selection"]
  90.             self.setselection(selstart, selend)
  91.         self.open()
  92.         self.setinfotext()
  93.         self.globals = {}
  94.         self._buf = ""  # for write method
  95.         self.debugging = 0
  96.         self.profiling = 0
  97.         if self.settings.has_key("run_as_main"):
  98.             self.run_as_main = self.settings["run_as_main"]
  99.         else:
  100.             self.run_as_main = 0
  101.     
  102.     def readwindowsettings(self):
  103.         try:
  104.             resref = Res.OpenResFile(self.path)
  105.         except Res.Error:
  106.             return
  107.         try:
  108.             Res.UseResFile(resref)
  109.             data = Res.Get1Resource('PyWS', 128)
  110.             self.settings = marshal.loads(data.data)
  111.         except:
  112.             pass
  113.         Res.CloseResFile(resref)
  114.         
  115.     def writewindowsettings(self):
  116.         try:
  117.             resref = Res.OpenResFile(self.path)
  118.         except Res.Error:
  119.             Res.CreateResFile(self.path)
  120.             resref = Res.OpenResFile(self.path)
  121.         try:
  122.             data = Res.Resource(marshal.dumps(self.settings))
  123.             Res.UseResFile(resref)
  124.             try:
  125.                 temp = Res.Get1Resource('PyWS', 128)
  126.                 temp.RemoveResource()
  127.             except Res.Error:
  128.                 pass
  129.             data.AddResource('PyWS', 128, "window settings")
  130.         finally:
  131.             Res.UpdateResFile(resref)
  132.             Res.CloseResFile(resref)
  133.     
  134.     def getsettings(self):
  135.         self.settings = {}
  136.         self.settings["windowbounds"] = self.getbounds()
  137.         self.settings["selection"] = self.getselection()
  138.         self.settings["fontsettings"] = self.editgroup.editor.getfontsettings()
  139.         self.settings["tabsize"] = self.editgroup.editor.gettabsettings()
  140.         self.settings["run_as_main"] = self.run_as_main
  141.     
  142.     def get(self):
  143.         return self.editgroup.editor.get()
  144.     
  145.     def getselection(self):
  146.         return self.editgroup.editor.ted.WEGetSelection()
  147.     
  148.     def setselection(self, selstart, selend):
  149.         self.editgroup.editor.setselection(selstart, selend)
  150.     
  151.     def getfilename(self):
  152.         if self.path:
  153.             return self.path
  154.         return '<%s>' % self.title
  155.     
  156.     def setupwidgets(self, text):
  157.         topbarheight = 24
  158.         popfieldwidth = 80
  159.         self.lastlineno = None
  160.         
  161.         # make an editor
  162.         self.editgroup = W.Group((0, topbarheight + 1, 0, 0))
  163.         editor = W.PyEditor((0, 0, -15,-15), text, 
  164.                 fontsettings = self.fontsettings, 
  165.                 tabsettings = self.tabsettings,
  166.                 file = self.getfilename())
  167.         
  168.         # make the widgets
  169.         self.popfield = ClassFinder((popfieldwidth - 17, -15, 16, 16), [], self.popselectline)
  170.         self.linefield = W.EditText((-1, -15, popfieldwidth - 15, 16), inset = (6, 1))
  171.         self.editgroup._barx = W.Scrollbar((popfieldwidth - 2, -15, -14, 16), editor.hscroll, max = 32767)
  172.         self.editgroup._bary = W.Scrollbar((-15, 14, 16, -14), editor.vscroll, max = 32767)
  173.         self.editgroup.editor = editor    # add editor *after* scrollbars
  174.         
  175.         self.editgroup.optionsmenu = W.PopupMenu((-15, -1, 16, 16), [])
  176.         self.editgroup.optionsmenu.bind('<click>', self.makeoptionsmenu)
  177.         
  178.         self.bevelbox = W.BevelBox((0, 0, 0, topbarheight))
  179.         self.hline = W.HorizontalLine((0, topbarheight, 0, 0))
  180.         self.infotext = W.TextBox((175, 6, -4, 14), backgroundcolor = (0xe000, 0xe000, 0xe000))
  181.         self.runbutton = W.Button((5, 4, 80, 16), "Run all", self.run)
  182.         self.runselbutton = W.Button((90, 4, 80, 16), "Run selection", self.runselection)
  183.         
  184.         # bind some keys
  185.         editor.bind("cmdr", self.runbutton.push)
  186.         editor.bind("enter", self.runselbutton.push)
  187.         editor.bind("cmdj", self.domenu_gotoline)
  188.         editor.bind("cmdd", self.domenu_toggledebugger)
  189.         editor.bind("<idle>", self.updateselection)
  190.         
  191.         editor.bind("cmde", searchengine.setfindstring)
  192.         editor.bind("cmdf", searchengine.show)
  193.         editor.bind("cmdg", searchengine.findnext)
  194.         editor.bind("cmdshiftr", searchengine.replace)
  195.         editor.bind("cmdt", searchengine.replacefind)
  196.         
  197.         self.linefield.bind("return", self.dolinefield)
  198.         self.linefield.bind("enter", self.dolinefield)
  199.         self.linefield.bind("tab", self.dolinefield)
  200.         
  201.         # intercept clicks
  202.         editor.bind("<click>", self.clickeditor)
  203.         self.linefield.bind("<click>", self.clicklinefield)
  204.     
  205.     def makeoptionsmenu(self):
  206.         menuitems = [('Font settings…', self.domenu_fontsettings), 
  207.                 ("Save options…", self.domenu_options),
  208.                 '-',
  209.                 ('\0' + chr(self.run_as_main) + 'Run as __main__', self.domenu_toggle_run_as_main), 
  210.                 ('Modularize', self.domenu_modularize),
  211.                 ('Browse namespace…', self.domenu_browsenamespace), 
  212.                 '-']
  213.         if self.profiling:
  214.             menuitems = menuitems + [('Disable profiler', self.domenu_toggleprofiler)]
  215.         else:
  216.             menuitems = menuitems + [('Enable profiler', self.domenu_toggleprofiler)]
  217.         if self.editgroup.editor._debugger:
  218.             menuitems = menuitems + [('Disable debugger', self.domenu_toggledebugger),
  219.                 ('Clear breakpoints', self.domenu_clearbreakpoints),
  220.                 ('Edit breakpoints…', self.domenu_editbreakpoints)]
  221.         else:
  222.             menuitems = menuitems + [('Enable debugger', self.domenu_toggledebugger)]
  223.         self.editgroup.optionsmenu.set(menuitems)
  224.     
  225.     def domenu_toggle_run_as_main(self):
  226.         self.run_as_main = not self.run_as_main
  227.         self.editgroup.editor.selchanged = 1
  228.     
  229.     def showbreakpoints(self, onoff):
  230.         self.editgroup.editor.showbreakpoints(onoff)
  231.         self.debugging = onoff
  232.     
  233.     def domenu_clearbreakpoints(self, *args):
  234.         self.editgroup.editor.clearbreakpoints()
  235.     
  236.     def domenu_editbreakpoints(self, *args):
  237.         self.editgroup.editor.editbreakpoints()
  238.     
  239.     def domenu_toggledebugger(self, *args):
  240.         if not self.debugging:
  241.             W.SetCursor('watch')
  242.         self.debugging = not self.debugging
  243.         self.editgroup.editor.togglebreakpoints()
  244.         
  245.     def domenu_toggleprofiler(self, *args):
  246.         self.profiling = not self.profiling
  247.     
  248.     def domenu_browsenamespace(self, *args):
  249.         import PyBrowser, W
  250.         W.SetCursor('watch')
  251.         globals, file, modname = self.getenvironment()
  252.         if not modname:
  253.             modname = self.title
  254.         PyBrowser.Browser(globals, "Object browser: " + modname)
  255.     
  256.     def domenu_modularize(self, *args):
  257.         modname = _filename_as_modname(self.title)
  258.         if not modname:
  259.             raise W.AlertError, 'Can’t modularize “%s”' % self.title
  260.         run_as_main = self.run_as_main
  261.         self.run_as_main = 0
  262.         self.run()
  263.         self.run_as_main = run_as_main
  264.         if self.path:
  265.             file = self.path
  266.         else:
  267.             file = self.title
  268.         
  269.         if self.globals and not sys.modules.has_key(modname):
  270.             module = imp.new_module(modname)
  271.             for attr in self.globals.keys():
  272.                 setattr(module,attr,self.globals[attr])
  273.             sys.modules[modname] = module
  274.             self.globals = {}
  275.     
  276.     def domenu_fontsettings(self, *args):
  277.         import FontSettings
  278.         fontsettings = self.editgroup.editor.getfontsettings()
  279.         tabsettings = self.editgroup.editor.gettabsettings()
  280.         settings = FontSettings.FontDialog(fontsettings, tabsettings)
  281.         if settings:
  282.             fontsettings, tabsettings = settings
  283.             self.editgroup.editor.setfontsettings(fontsettings)
  284.             self.editgroup.editor.settabsettings(tabsettings)
  285.     
  286.     def domenu_options(self, *args):
  287.         rv = SaveOptions(self._creator)
  288.         if rv:
  289.             self.editgroup.editor.selchanged = 1 # ouch...
  290.             self._creator = rv
  291.     
  292.     def clicklinefield(self):
  293.         if self._currentwidget <> self.linefield:
  294.             self.linefield.select(1)
  295.             self.linefield.selectall()
  296.             return 1
  297.     
  298.     def clickeditor(self):
  299.         if self._currentwidget <> self.editgroup.editor:
  300.             self.dolinefield()
  301.             return 1
  302.     
  303.     def updateselection(self, force = 0):
  304.         sel = min(self.editgroup.editor.getselection())
  305.         lineno = self.editgroup.editor.offsettoline(sel)
  306.         if lineno <> self.lastlineno or force:
  307.             self.lastlineno = lineno
  308.             self.linefield.set(str(lineno + 1))
  309.             self.linefield.selview()
  310.     
  311.     def dolinefield(self):
  312.         try:
  313.             lineno = string.atoi(self.linefield.get()) - 1
  314.             if lineno <> self.lastlineno:
  315.                 self.editgroup.editor.selectline(lineno)
  316.                 self.updateselection(1)
  317.         except:
  318.             self.updateselection(1)
  319.         self.editgroup.editor.select(1)
  320.     
  321.     def setinfotext(self):
  322.         if not hasattr(self, 'infotext'):
  323.             return
  324.         if self.path:
  325.             self.infotext.set(self.path)
  326.         else:
  327.             self.infotext.set("")
  328.     
  329.     def close(self):
  330.         if self.editgroup.editor.changed:
  331.             import EasyDialogs
  332.             import Qd
  333.             Qd.InitCursor() # XXX should be done by dialog
  334.             save = EasyDialogs.AskYesNoCancel('Save window “%s” before closing?' % self.title, 1)
  335.             if save > 0:
  336.                 if self.domenu_save():
  337.                     return 1
  338.             elif save < 0:
  339.                 return 1
  340.         self.globals = None        # XXX doesn't help... all globals leak :-(
  341.         W.Window.close(self)
  342.     
  343.     def domenu_close(self, *args):
  344.         return self.close()
  345.     
  346.     def domenu_print(self, *args):
  347.         import Fm
  348.         import Qd
  349.         import Printing
  350.         
  351.         # get the application's .pageSetup record
  352.         pageSetup = W.getapplication().pageSetup
  353.         # (if we need to create a default one, here's how to do it:)
  354.         # pageSetup = Printing.NewTPrintRecord()
  355.         # Printing.PrintDefault(pageSetup)
  356.         
  357.         # present the print dialog, ok is 0 if user cancels
  358.         ok = Printing.PrJobDialog(pageSetup)
  359.         if not ok: return
  360.         
  361.         # get font settings (must be set for every page)
  362.         face,style,size,color = self.editgroup.editor.getfontsettings()
  363.         face = Fm.GetFNum(face)
  364.         
  365.         # set up printing port
  366.         port = Printing.PrOpenDoc(pageSetup)
  367.         try:
  368.             # now, format the document one page at a time
  369.             pytext = self.editgroup.editor.get()
  370.             lines = string.split(pytext, '\r')
  371.             qtylines = len(lines)
  372.             line = 0
  373.             
  374.             # where to position the upper-left corner of text
  375.             x = 0        # half inch
  376.             y = 0
  377.             dy = size + 1    # line spacing -- should use Fm.FontMetrics() instead (<-- HACK!)
  378.             
  379.             # how many lines on a page?!?
  380.             linesPerPage = 72*10 / dy        # <-- HACK!
  381.             
  382.             while line < qtylines:
  383.                 Printing.PrOpenPage(port, None)
  384.                 try:
  385.                     # set up font
  386.                     Qd.TextFont(face)
  387.                     Qd.TextSize(size)
  388.                     Qd.TextFace(style)
  389.                     
  390.                     # draw the lines
  391.                     for i in range(min(linesPerPage,qtylines-line)):
  392.                         Qd.MoveTo(x,y)
  393.                         Qd.RGBForeColor((40000,40000,40000))
  394.                         Qd.DrawString("%05d: " % line)    # draw line number in light gray
  395.                         Qd.RGBForeColor((0,0,0))        # draw rest of line in black
  396.                         # HACK: replace tabs with spaces
  397.                         Qd.DrawString( string.replace(lines[line], '\t', "    ") )
  398.                         line = line + 1
  399.                         y = y + dy
  400.                     y = y - dy*i
  401.                 finally:
  402.                     # close the page
  403.                     Printing.PrClosePage(port)
  404.         finally:
  405.             # close the printing port
  406.             Printing.PrCloseDoc(port)
  407.  
  408.     def domenu_save(self, *args):
  409.         if not self.path:
  410.             # Will call us recursively
  411.             return self.domenu_save_as()
  412.         data = self.editgroup.editor.get()
  413.         fp = open(self.path, 'wb')  # open file in binary mode, data has '\r' line-endings
  414.         fp.write(data)
  415.         fp.close()
  416.         fss = macfs.FSSpec(self.path)
  417.         fss.SetCreatorType(self._creator, 'TEXT')
  418.         self.getsettings()
  419.         self.writewindowsettings()
  420.         self.editgroup.editor.changed = 0
  421.         self.editgroup.editor.selchanged = 0
  422.         import linecache
  423.         if linecache.cache.has_key(self.path):
  424.             del linecache.cache[self.path]
  425.         import macostools
  426.         macostools.touched(self.path)
  427.     
  428.     def can_save(self, menuitem):
  429.         return self.editgroup.editor.changed or self.editgroup.editor.selchanged
  430.     
  431.     def domenu_save_as(self, *args):
  432.         fss, ok = macfs.StandardPutFile('Save as:', self.title)
  433.         if not ok: 
  434.             return 1
  435.         self.showbreakpoints(0)
  436.         self.path = fss.as_pathname()
  437.         self.setinfotext()
  438.         self.title = os.path.split(self.path)[-1]
  439.         self.wid.SetWTitle(self.title)
  440.         self.domenu_save()
  441.         self.editgroup.editor.setfile(self.getfilename())
  442.         app = W.getapplication()
  443.         app.makeopenwindowsmenu()
  444.         if hasattr(app, 'makescriptsmenu'):
  445.             app = W.getapplication()
  446.             fss, fss_changed = app.scriptsfolder.Resolve()
  447.             path = fss.as_pathname()
  448.             if path == self.path[:len(path)]:
  449.                 W.getapplication().makescriptsmenu()
  450.     
  451.     def domenu_save_as_applet(self, *args):
  452.         try:
  453.             import buildtools
  454.         except ImportError:
  455.             # only have buildtools in Python >= 1.5.2
  456.             raise W.AlertError, "“Save as Applet” is only supported in\rPython 1.5.2 and up."
  457.         
  458.         buildtools.DEBUG = 0    # ouch.
  459.         
  460.         if self.title[-3:] == ".py":
  461.             destname = self.title[:-3]
  462.         else:
  463.             destname = self.title + ".applet"
  464.         fss, ok = macfs.StandardPutFile('Save as Applet:', destname)
  465.         if not ok: 
  466.             return 1
  467.         W.SetCursor("watch")
  468.         destname = fss.as_pathname()
  469.         if self.path:
  470.             filename = self.path
  471.             if filename[-3:] == ".py":
  472.                 rsrcname = filename[:-3] + '.rsrc'
  473.             else:
  474.                 rsrcname = filename + '.rsrc'
  475.         else:
  476.             filename = self.title
  477.             rsrcname = ""
  478.         
  479.         pytext = self.editgroup.editor.get()
  480.         pytext = string.split(pytext, '\r')
  481.         pytext = string.join(pytext, '\n') + '\n'
  482.         try:
  483.             code = compile(pytext, filename, "exec")
  484.         except (SyntaxError, EOFError):
  485.             raise buildtools.BuildError, "Syntax error in script %s" % `filename`
  486.         
  487.         # Try removing the output file
  488.         try:
  489.             os.remove(destname)
  490.         except os.error:
  491.             pass
  492.         template = buildtools.findtemplate()
  493.         buildtools.process_common(template, None, code, rsrcname, destname, 0, 1)
  494.     
  495.     def domenu_gotoline(self, *args):
  496.         self.linefield.selectall()
  497.         self.linefield.select(1)
  498.         self.linefield.selectall()
  499.     
  500.     def domenu_selectline(self, *args):
  501.         self.editgroup.editor.expandselection()
  502.     
  503.     def domenu_find(self, *args):
  504.         searchengine.show()
  505.     
  506.     def domenu_entersearchstring(self, *args):
  507.         searchengine.setfindstring()
  508.     
  509.     def domenu_replace(self, *args):
  510.         searchengine.replace()
  511.     
  512.     def domenu_findnext(self, *args):
  513.         searchengine.findnext()
  514.     
  515.     def domenu_replacefind(self, *args):
  516.         searchengine.replacefind()
  517.     
  518.     def domenu_run(self, *args):
  519.         self.runbutton.push()
  520.     
  521.     def domenu_runselection(self, *args):
  522.         self.runselbutton.push()
  523.     
  524.     def run(self):
  525.         self._run()
  526.     
  527.     def _run(self):
  528.         pytext = self.editgroup.editor.get()
  529.         globals, file, modname = self.getenvironment()
  530.         self.execstring(pytext, globals, globals, file, modname)
  531.     
  532.     def runselection(self):
  533.         self._runselection()
  534.     
  535.     def _runselection(self):
  536.         globals, file, modname = self.getenvironment()
  537.         locals = globals
  538.         # select whole lines
  539.         self.editgroup.editor.expandselection()
  540.         
  541.         # get lineno of first selected line
  542.         selstart, selend = self.editgroup.editor.getselection()
  543.         selstart, selend = min(selstart, selend), max(selstart, selend)
  544.         selfirstline = self.editgroup.editor.offsettoline(selstart)
  545.         alltext = self.editgroup.editor.get()
  546.         pytext = alltext[selstart:selend]
  547.         lines = string.split(pytext, '\r')
  548.         indent = getminindent(lines)
  549.         if indent == 1:
  550.             classname = ''
  551.             alllines = string.split(alltext, '\r')
  552.             identifieRE_match = _identifieRE.match
  553.             for i in range(selfirstline - 1, -1, -1):
  554.                 line = alllines[i]
  555.                 if line[:6] == 'class ':
  556.                     classname = string.split(string.strip(line[6:]))[0]
  557.                     classend = identifieRE_match(classname)
  558.                     if classend < 1:
  559.                         raise W.AlertError, 'Can’t find a class.'
  560.                     classname = classname[:classend]
  561.                     break
  562.                 elif line and line[0] not in '\t#':
  563.                     raise W.AlertError, 'Can’t find a class.'
  564.             else:
  565.                 raise W.AlertError, 'Can’t find a class.'
  566.             if globals.has_key(classname):
  567.                 locals = globals[classname].__dict__
  568.             else:
  569.                 raise W.AlertError, 'Can’t find class “%s”.' % classname
  570.             # dedent to top level
  571.             for i in range(len(lines)):
  572.                 lines[i] = lines[i][1:]
  573.             pytext = string.join(lines, '\r')
  574.         elif indent > 0:
  575.             raise W.AlertError, 'Can’t run indented code.'
  576.         
  577.         # add "newlines" to fool compile/exec: 
  578.         # now a traceback will give the right line number
  579.         pytext = selfirstline * '\r' + pytext
  580.         self.execstring(pytext, globals, locals, file, modname)
  581.     
  582.     def execstring(self, pytext, globals, locals, file, modname):
  583.         tracebackwindow.hide()
  584.         # update windows
  585.         W.getapplication().refreshwindows()
  586.         if self.run_as_main:
  587.             modname = "__main__"
  588.         if self.path:
  589.             dir = os.path.dirname(self.path)
  590.             savedir = os.getcwd()
  591.             os.chdir(dir)
  592.             sys.path.insert(0, dir)
  593.         else:
  594.             cwdindex = None
  595.         try:
  596.             execstring(pytext, globals, locals, file, self.debugging, 
  597.                     modname, self.profiling)
  598.         finally:
  599.             if self.path:
  600.                 os.chdir(savedir)
  601.                 del sys.path[0]
  602.     
  603.     def getenvironment(self):
  604.         if self.path:
  605.             file = self.path
  606.             dir = os.path.dirname(file)
  607.             # check if we're part of a package
  608.             modname = ""
  609.             while os.path.exists(os.path.join(dir, "__init__.py")):
  610.                 dir, dirname = os.path.split(dir)
  611.                 modname = dirname + '.' + modname
  612.             subname = _filename_as_modname(self.title)
  613.             if modname:
  614.                 if subname == "__init__":
  615.                     # strip trailing period
  616.                     modname = modname[:-1]
  617.                 else:
  618.                     modname = modname + subname
  619.             else:
  620.                 modname = subname
  621.             if sys.modules.has_key(modname):
  622.                 globals = sys.modules[modname].__dict__
  623.                 self.globals = {}
  624.             else:
  625.                 globals = self.globals
  626.         else:
  627.             file = '<%s>' % self.title
  628.             globals = self.globals
  629.             modname = file
  630.         return globals, file, modname
  631.     
  632.     def write(self, stuff):
  633.         """for use as stdout"""
  634.         self._buf = self._buf + stuff
  635.         if '\n' in self._buf:
  636.             self.flush()
  637.     
  638.     def flush(self):
  639.         stuff = string.split(self._buf, '\n')
  640.         stuff = string.join(stuff, '\r')
  641.         end = self.editgroup.editor.ted.WEGetTextLength()
  642.         self.editgroup.editor.ted.WESetSelection(end, end)
  643.         self.editgroup.editor.ted.WEInsert(stuff, None, None)
  644.         self.editgroup.editor.updatescrollbars()
  645.         self._buf = ""
  646.         # ? optional:
  647.         #self.wid.SelectWindow()
  648.     
  649.     def getclasslist(self):
  650.         from string import find, strip
  651.         editor = self.editgroup.editor
  652.         text = editor.get()
  653.         list = []
  654.         append = list.append
  655.         functag = "func"
  656.         classtag = "class"
  657.         methodtag = "method"
  658.         pos = -1
  659.         if text[:4] == 'def ':
  660.             append((pos + 4, functag))
  661.             pos = 4
  662.         while 1:
  663.             pos = find(text, '\rdef ', pos + 1)
  664.             if pos < 0:
  665.                 break
  666.             append((pos + 5, functag))
  667.         pos = -1
  668.         if text[:6] == 'class ':
  669.             append((pos + 6, classtag))
  670.             pos = 6
  671.         while 1:
  672.             pos = find(text, '\rclass ', pos + 1)
  673.             if pos < 0:
  674.                 break
  675.             append((pos + 7, classtag))
  676.         pos = 0
  677.         while 1:
  678.             pos = find(text, '\r\tdef ', pos + 1)
  679.             if pos < 0:
  680.                 break
  681.             append((pos + 6, methodtag))
  682.         list.sort()
  683.         classlist = []
  684.         methodlistappend = None
  685.         offsetToLine = editor.ted.WEOffsetToLine
  686.         getLineRange = editor.ted.WEGetLineRange
  687.         append = classlist.append
  688.         identifieRE_match = _identifieRE.match
  689.         for pos, tag in list:
  690.             lineno = offsetToLine(pos)
  691.             lineStart, lineEnd = getLineRange(lineno)
  692.             line = strip(text[pos:lineEnd])
  693.             line = line[:identifieRE_match(line)]
  694.             if tag is functag:
  695.                 append(("def " + line, lineno + 1))
  696.                 methodlistappend = None
  697.             elif tag is classtag:
  698.                 append(["class " + line])
  699.                 methodlistappend = classlist[-1].append
  700.             elif methodlistappend and tag is methodtag:
  701.                 methodlistappend(("def " + line, lineno + 1))
  702.         return classlist
  703.     
  704.     def popselectline(self, lineno):
  705.         self.editgroup.editor.selectline(lineno - 1)
  706.     
  707.     def selectline(self, lineno, charoffset = 0):
  708.         self.editgroup.editor.selectline(lineno - 1, charoffset)
  709.  
  710. class _saveoptions:
  711.     
  712.     def __init__(self, creator):
  713.         self.rv = None
  714.         self.w = w = W.ModalDialog((240, 140), 'Save options')
  715.         radiobuttons = []
  716.         w.label = W.TextBox((8, 8, 80, 18), "File creator:")
  717.         w.ide_radio = W.RadioButton((8, 22, 160, 18), "This application", radiobuttons, self.ide_hit)
  718.         w.interp_radio = W.RadioButton((8, 42, 160, 18), "Python Interpreter", radiobuttons, self.interp_hit)
  719.         w.other_radio = W.RadioButton((8, 62, 50, 18), "Other:", radiobuttons)
  720.         w.other_creator = W.EditText((62, 62, 40, 20), creator, self.otherselect)
  721.         w.cancelbutton = W.Button((-180, -30, 80, 16), "Cancel", self.cancelbuttonhit)
  722.         w.okbutton = W.Button((-90, -30, 80, 16), "Done", self.okbuttonhit)
  723.         w.setdefaultbutton(w.okbutton)
  724.         if creator == 'Pyth':
  725.             w.interp_radio.set(1)
  726.         elif creator == W._signature:
  727.             w.ide_radio.set(1)
  728.         else:
  729.             w.other_radio.set(1)
  730.         w.bind("cmd.", w.cancelbutton.push)
  731.         w.open()
  732.     
  733.     def ide_hit(self):
  734.         self.w.other_creator.set(W._signature)
  735.     
  736.     def interp_hit(self):
  737.         self.w.other_creator.set("Pyth")
  738.     
  739.     def otherselect(self, *args):
  740.         sel_from, sel_to = self.w.other_creator.getselection()
  741.         creator = self.w.other_creator.get()[:4]
  742.         creator = creator + " " * (4 - len(creator))
  743.         self.w.other_creator.set(creator)
  744.         self.w.other_creator.setselection(sel_from, sel_to)
  745.         self.w.other_radio.set(1)
  746.     
  747.     def cancelbuttonhit(self):
  748.         self.w.close()
  749.     
  750.     def okbuttonhit(self):
  751.         self.rv = self.w.other_creator.get()[:4]
  752.         self.w.close()
  753.  
  754.  
  755. def SaveOptions(creator):
  756.     s = _saveoptions(creator)
  757.     return s.rv
  758.  
  759.  
  760. def _escape(where, what) : 
  761.     return string.join(string.split(where, what), '\\' + what)
  762.  
  763. def _makewholewordpattern(word):
  764.     # first, escape special regex chars
  765.     for esc in "\\[].*^+$?":
  766.         word = _escape(word, esc)
  767.     import regex
  768.     notwordcharspat = '[^' + _wordchars + ']'
  769.     pattern = '\(' + word + '\)'
  770.     if word[0] in _wordchars:
  771.         pattern = notwordcharspat + pattern
  772.     if word[-1] in _wordchars:
  773.         pattern = pattern + notwordcharspat
  774.     return regex.compile(pattern)
  775.  
  776. class SearchEngine:
  777.     
  778.     def __init__(self):
  779.         self.visible = 0
  780.         self.w = None
  781.         self.parms = {  "find": "",
  782.                     "replace": "",
  783.                     "wrap": 1,
  784.                     "casesens": 1,
  785.                     "wholeword": 1
  786.                 }
  787.         import MacPrefs
  788.         prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  789.         if prefs.searchengine:
  790.             self.parms["casesens"] = prefs.searchengine.casesens
  791.             self.parms["wrap"] = prefs.searchengine.wrap
  792.             self.parms["wholeword"] = prefs.searchengine.wholeword
  793.     
  794.     def show(self):
  795.         self.visible = 1
  796.         if self.w:
  797.             self.w.wid.ShowWindow()
  798.             self.w.wid.SelectWindow()
  799.             self.w.find.edit.select(1)
  800.             self.w.find.edit.selectall()
  801.             return
  802.         self.w = W.Dialog((420, 150), "Find")
  803.         
  804.         self.w.find = TitledEditText((10, 4, 300, 36), "Search for:")
  805.         self.w.replace = TitledEditText((10, 100, 300, 36), "Replace with:")
  806.         
  807.         self.w.boxes = W.Group((10, 50, 300, 40))
  808.         self.w.boxes.casesens = W.CheckBox((0, 0, 100, 16), "Case sensitive")
  809.         self.w.boxes.wholeword = W.CheckBox((0, 20, 100, 16), "Whole word")
  810.         self.w.boxes.wrap = W.CheckBox((110, 0, 100, 16), "Wrap around")
  811.         
  812.         self.buttons = [    ("Find",        "cmdf",     self.find), 
  813.                     ("Replace",         "cmdr",     self.replace), 
  814.                     ("Replace all",     None,   self.replaceall), 
  815.                     ("Don’t find",  "cmdd",     self.dont), 
  816.                     ("Cancel",          "cmd.",     self.cancel)
  817.                 ]
  818.         for i in range(len(self.buttons)):
  819.             bounds = -90, 22 + i * 24, 80, 16
  820.             title, shortcut, callback = self.buttons[i]
  821.             self.w[title] = W.Button(bounds, title, callback)
  822.             if shortcut:
  823.                 self.w.bind(shortcut, self.w[title].push)
  824.         self.w.setdefaultbutton(self.w["Don’t find"])
  825.         self.w.find.edit.bind("<key>", self.key)
  826.         self.w.bind("<activate>", self.activate)
  827.         self.w.bind("<close>", self.close)
  828.         self.w.open()
  829.         self.setparms()
  830.         self.w.find.edit.select(1)
  831.         self.w.find.edit.selectall()
  832.         self.checkbuttons()
  833.     
  834.     def close(self):
  835.         self.hide()
  836.         return -1
  837.     
  838.     def key(self, char, modifiers):
  839.         self.w.find.edit.key(char, modifiers)
  840.         self.checkbuttons()
  841.         return 1
  842.     
  843.     def activate(self, onoff):
  844.         if onoff:
  845.             self.checkbuttons()
  846.     
  847.     def checkbuttons(self):
  848.         editor = findeditor(self)
  849.         if editor:
  850.             if self.w.find.get():
  851.                 for title, cmd, call in self.buttons[:-2]:
  852.                     self.w[title].enable(1)
  853.                 self.w.setdefaultbutton(self.w["Find"])
  854.             else:
  855.                 for title, cmd, call in self.buttons[:-2]:
  856.                     self.w[title].enable(0)
  857.                 self.w.setdefaultbutton(self.w["Don’t find"])
  858.         else:
  859.             for title, cmd, call in self.buttons[:-2]:
  860.                 self.w[title].enable(0)
  861.             self.w.setdefaultbutton(self.w["Don’t find"])
  862.     
  863.     def find(self):
  864.         self.getparmsfromwindow()
  865.         if self.findnext():
  866.             self.hide()
  867.     
  868.     def replace(self):
  869.         editor = findeditor(self)
  870.         if not editor:
  871.             return
  872.         if self.visible:
  873.             self.getparmsfromwindow()
  874.         text = editor.getselectedtext()
  875.         find = self.parms["find"]
  876.         if not self.parms["casesens"]:
  877.             find = string.lower(find)
  878.             text = string.lower(text)
  879.         if text == find:
  880.             self.hide()
  881.             editor.insert(self.parms["replace"])
  882.     
  883.     def replaceall(self):
  884.         editor = findeditor(self)
  885.         if not editor:
  886.             return
  887.         if self.visible:
  888.             self.getparmsfromwindow()
  889.         W.SetCursor("watch")
  890.         find = self.parms["find"]
  891.         if not find:
  892.             return
  893.         findlen = len(find)
  894.         replace = self.parms["replace"]
  895.         replacelen = len(replace)
  896.         Text = editor.get()
  897.         if not self.parms["casesens"]:
  898.             find = string.lower(find)
  899.             text = string.lower(Text)
  900.         else:
  901.             text = Text
  902.         newtext = ""
  903.         pos = 0
  904.         counter = 0
  905.         while 1:
  906.             if self.parms["wholeword"]:
  907.                 wholewordRE = _makewholewordpattern(find)
  908.                 wholewordRE.search(text, pos)
  909.                 if wholewordRE.regs:
  910.                     pos = wholewordRE.regs[1][0]
  911.                 else:
  912.                     pos = -1
  913.             else:
  914.                 pos = string.find(text, find, pos)
  915.             if pos < 0:
  916.                 break
  917.             counter = counter + 1
  918.             text = text[:pos] + replace + text[pos + findlen:]
  919.             Text = Text[:pos] + replace + Text[pos + findlen:]
  920.             pos = pos + replacelen
  921.         W.SetCursor("arrow")
  922.         if counter:
  923.             self.hide()
  924.             import EasyDialogs
  925.             import Res
  926.             editor.changed = 1
  927.             editor.selchanged = 1
  928.             editor.ted.WEUseText(Res.Resource(Text))
  929.             editor.ted.WECalText()
  930.             editor.SetPort()
  931.             Win.InvalRect(editor._bounds)
  932.             #editor.ted.WEUpdate(self.w.wid.GetWindowPort().visRgn)
  933.             EasyDialogs.Message("Replaced %d occurrences" % counter)
  934.     
  935.     def dont(self):
  936.         self.getparmsfromwindow()
  937.         self.hide()
  938.     
  939.     def replacefind(self):
  940.         self.replace()
  941.         self.findnext()
  942.     
  943.     def setfindstring(self):
  944.         editor = findeditor(self)
  945.         if not editor:
  946.             return
  947.         find = editor.getselectedtext()
  948.         if not find:
  949.             return
  950.         self.parms["find"] = find
  951.         if self.w:
  952.             self.w.find.edit.set(self.parms["find"])
  953.             self.w.find.edit.selectall()
  954.     
  955.     def findnext(self):
  956.         editor = findeditor(self)
  957.         if not editor:
  958.             return
  959.         find = self.parms["find"]
  960.         if not find:
  961.             return
  962.         text = editor.get()
  963.         if not self.parms["casesens"]:
  964.             find = string.lower(find)
  965.             text = string.lower(text)
  966.         selstart, selend = editor.getselection()
  967.         selstart, selend = min(selstart, selend), max(selstart, selend)
  968.         if self.parms["wholeword"]:
  969.             wholewordRE = _makewholewordpattern(find)
  970.             wholewordRE.search(text, selend)
  971.             if wholewordRE.regs:
  972.                 pos = wholewordRE.regs[1][0]
  973.             else:
  974.                 pos = -1
  975.         else:
  976.             pos = string.find(text, find, selend)
  977.         if pos >= 0:
  978.             editor.setselection(pos, pos + len(find))
  979.             return 1
  980.         elif self.parms["wrap"]:
  981.             if self.parms["wholeword"]:
  982.                 wholewordRE.search(text, 0)
  983.                 if wholewordRE.regs:
  984.                     pos = wholewordRE.regs[1][0]
  985.                 else:
  986.                     pos = -1
  987.             else:
  988.                 pos = string.find(text, find)
  989.             if selstart > pos >= 0:
  990.                 editor.setselection(pos, pos + len(find))
  991.                 return 1
  992.     
  993.     def setparms(self):
  994.         for key, value in self.parms.items():
  995.             try:
  996.                 self.w[key].set(value)
  997.             except KeyError:
  998.                 self.w.boxes[key].set(value)
  999.     
  1000.     def getparmsfromwindow(self):
  1001.         if not self.w:
  1002.             return
  1003.         for key, value in self.parms.items():
  1004.             try:
  1005.                 value = self.w[key].get()
  1006.             except KeyError:
  1007.                 value = self.w.boxes[key].get()
  1008.             self.parms[key] = value
  1009.     
  1010.     def cancel(self):
  1011.         self.hide()
  1012.         self.setparms()
  1013.     
  1014.     def hide(self):
  1015.         if self.w:
  1016.             self.w.wid.HideWindow()
  1017.             self.visible = 0
  1018.     
  1019.     def writeprefs(self):
  1020.         import MacPrefs
  1021.         self.getparmsfromwindow()
  1022.         prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  1023.         prefs.searchengine.casesens = self.parms["casesens"]
  1024.         prefs.searchengine.wrap = self.parms["wrap"]
  1025.         prefs.searchengine.wholeword = self.parms["wholeword"]
  1026.         prefs.save()
  1027.     
  1028.  
  1029. class TitledEditText(W.Group):
  1030.     
  1031.     def __init__(self, possize, title, text = ""):
  1032.         W.Group.__init__(self, possize)
  1033.         self.title = W.TextBox((0, 0, 0, 16), title)
  1034.         self.edit = W.EditText((0, 16, 0, 0), text)
  1035.     
  1036.     def set(self, value):
  1037.         self.edit.set(value)
  1038.     
  1039.     def get(self):
  1040.         return self.edit.get()
  1041.  
  1042.  
  1043. class ClassFinder(W.PopupWidget):
  1044.     
  1045.     def click(self, point, modifiers):
  1046.         W.SetCursor("watch")
  1047.         self.set(self._parentwindow.getclasslist())
  1048.         W.PopupWidget.click(self, point, modifiers)
  1049.  
  1050.  
  1051. def getminindent(lines):
  1052.     indent = -1
  1053.     for line in lines:
  1054.         stripped = string.strip(line)
  1055.         if not stripped or stripped[0] == '#':
  1056.             continue
  1057.         if indent < 0 or line[:indent] <> indent * '\t':
  1058.             indent = 0
  1059.             for c in line:
  1060.                 if c <> '\t':
  1061.                     break
  1062.                 indent = indent + 1
  1063.     return indent
  1064.  
  1065.  
  1066. def getoptionkey():
  1067.     return not not ord(Evt.GetKeys()[7]) & 0x04
  1068.  
  1069.  
  1070. def execstring(pytext, globals, locals, filename="<string>", debugging=0, 
  1071.             modname="__main__", profiling=0):
  1072.     if debugging:
  1073.         import PyDebugger, bdb
  1074.         BdbQuit = bdb.BdbQuit
  1075.     else:
  1076.         BdbQuit = 'BdbQuitDummyException'
  1077.     pytext = string.split(pytext, '\r')
  1078.     pytext = string.join(pytext, '\n') + '\n'
  1079.     W.SetCursor("watch")
  1080.     globals['__name__'] = modname
  1081.     globals['__file__'] = filename
  1082.     sys.argv = [filename]
  1083.     try:
  1084.         code = compile(pytext, filename, "exec")
  1085.     except:
  1086.         # XXXX BAAAADDD.... We let tracebackwindow decide to treat SyntaxError 
  1087.         # special. That's wrong because THIS case is special (could be literal 
  1088.         # overflow!) and SyntaxError could mean we need a traceback (syntax error 
  1089.         # in imported module!!!
  1090.         tracebackwindow.traceback(1, filename)
  1091.         return
  1092.     try:
  1093.         if debugging:
  1094.             PyDebugger.startfromhere()
  1095.         else:
  1096.             MacOS.EnableAppswitch(0)
  1097.         try:
  1098.             if profiling:
  1099.                 import profile, ProfileBrowser
  1100.                 p = profile.Profile()
  1101.                 p.set_cmd(filename)
  1102.                 try:
  1103.                     p.runctx(code, globals, locals)
  1104.                 finally:
  1105.                     import pstats
  1106.                     
  1107.                     stats = pstats.Stats(p)
  1108.                     ProfileBrowser.ProfileBrowser(stats)
  1109.             else:
  1110.                 exec code in globals, locals
  1111.         finally:
  1112.             MacOS.EnableAppswitch(-1)
  1113.     except W.AlertError, detail:
  1114.         raise W.AlertError, detail
  1115.     except (KeyboardInterrupt, BdbQuit):
  1116.         pass
  1117.     except:
  1118.         if debugging:
  1119.             sys.settrace(None)
  1120.             PyDebugger.postmortem(sys.exc_type, sys.exc_value, sys.exc_traceback)
  1121.             return
  1122.         else:
  1123.             tracebackwindow.traceback(1, filename)
  1124.     if debugging:
  1125.         sys.settrace(None)
  1126.         PyDebugger.stop()
  1127.  
  1128.  
  1129. _identifieRE = regex.compile("[A-Za-z_][A-Za-z_0-9]*")
  1130.  
  1131. def _filename_as_modname(fname):
  1132.     if fname[-3:] == '.py':
  1133.         modname = fname[:-3]
  1134.         if _identifieRE.match(modname) == len(modname):
  1135.             return string.join(string.split(modname, '.'), '_')
  1136.  
  1137. def findeditor(topwindow, fromtop = 0):
  1138.     wid = Win.FrontWindow()
  1139.     if not fromtop:
  1140.         if topwindow.w and wid == topwindow.w.wid:
  1141.             wid = topwindow.w.wid.GetNextWindow()
  1142.     if not wid:
  1143.         return
  1144.     app = W.getapplication()
  1145.     if app._windows.has_key(wid): # KeyError otherwise can happen in RoboFog :-(
  1146.         window = W.getapplication()._windows[wid]
  1147.     else:
  1148.         return
  1149.     if not isinstance(window, Editor):
  1150.         return
  1151.     return window.editgroup.editor
  1152.  
  1153.  
  1154. class _EditorDefaultSettings:
  1155.     
  1156.     def __init__(self):
  1157.         self.template = "%s, %d point"
  1158.         self.fontsettings, self.tabsettings, self.windowsize = geteditorprefs()
  1159.         self.w = W.Dialog((328, 120), "Editor default settings")
  1160.         self.w.setfontbutton = W.Button((8, 8, 80, 16), "Set font…", self.dofont)
  1161.         self.w.fonttext = W.TextBox((98, 10, -8, 14), self.template % (self.fontsettings[0], self.fontsettings[2]))
  1162.         
  1163.         self.w.picksizebutton = W.Button((8, 50, 80, 16), "Front window", self.picksize)
  1164.         self.w.xsizelabel = W.TextBox((98, 32, 40, 14), "Width:")
  1165.         self.w.ysizelabel = W.TextBox((148, 32, 40, 14), "Height:")
  1166.         self.w.xsize = W.EditText((98, 48, 40, 20), `self.windowsize[0]`)
  1167.         self.w.ysize = W.EditText((148, 48, 40, 20), `self.windowsize[1]`)
  1168.         
  1169.         self.w.cancelbutton = W.Button((-180, -26, 80, 16), "Cancel", self.cancel)
  1170.         self.w.okbutton = W.Button((-90, -26, 80, 16), "Done", self.ok)
  1171.         self.w.setdefaultbutton(self.w.okbutton)
  1172.         self.w.bind('cmd.', self.w.cancelbutton.push)
  1173.         self.w.open()
  1174.     
  1175.     def picksize(self):
  1176.         app = W.getapplication()
  1177.         editor = findeditor(self)
  1178.         if editor is not None:
  1179.             width, height = editor._parentwindow._bounds[2:]
  1180.             self.w.xsize.set(`width`)
  1181.             self.w.ysize.set(`height`)
  1182.         else:
  1183.             raise W.AlertError, "No edit window found"
  1184.     
  1185.     def dofont(self):
  1186.         import FontSettings
  1187.         settings = FontSettings.FontDialog(self.fontsettings, self.tabsettings)
  1188.         if settings:
  1189.             self.fontsettings, self.tabsettings = settings
  1190.             sys.exc_traceback = None
  1191.             self.w.fonttext.set(self.template % (self.fontsettings[0], self.fontsettings[2]))
  1192.     
  1193.     def close(self):
  1194.         self.w.close()
  1195.         del self.w
  1196.     
  1197.     def cancel(self):
  1198.         self.close()
  1199.     
  1200.     def ok(self):
  1201.         try:
  1202.             width = string.atoi(self.w.xsize.get())
  1203.         except:
  1204.             self.w.xsize.select(1)
  1205.             self.w.xsize.selectall()
  1206.             raise W.AlertError, "Bad number for window width"
  1207.         try:
  1208.             height = string.atoi(self.w.ysize.get())
  1209.         except:
  1210.             self.w.ysize.select(1)
  1211.             self.w.ysize.selectall()
  1212.             raise W.AlertError, "Bad number for window height"
  1213.         self.windowsize = width, height
  1214.         seteditorprefs(self.fontsettings, self.tabsettings, self.windowsize)
  1215.         self.close()
  1216.  
  1217. def geteditorprefs():
  1218.     import MacPrefs
  1219.     prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  1220.     try:
  1221.         fontsettings = prefs.pyedit.fontsettings
  1222.         tabsettings = prefs.pyedit.tabsettings
  1223.         windowsize = prefs.pyedit.windowsize
  1224.     except:
  1225.         fontsettings = prefs.pyedit.fontsettings = ("Python-Sans", 0, 9, (0, 0, 0))
  1226.         tabsettings = prefs.pyedit.tabsettings = (8, 1)
  1227.         windowsize = prefs.pyedit.windowsize = (500, 250)
  1228.         sys.exc_traceback = None
  1229.     return fontsettings, tabsettings, windowsize
  1230.  
  1231. def seteditorprefs(fontsettings, tabsettings, windowsize):
  1232.     import MacPrefs
  1233.     prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  1234.     prefs.pyedit.fontsettings = fontsettings
  1235.     prefs.pyedit.tabsettings = tabsettings
  1236.     prefs.pyedit.windowsize = windowsize
  1237.     prefs.save()
  1238.  
  1239. _defaultSettingsEditor = None
  1240.  
  1241. def EditorDefaultSettings():
  1242.     global _defaultSettingsEditor
  1243.     if _defaultSettingsEditor is None or not hasattr(_defaultSettingsEditor, "w"):
  1244.         _defaultSettingsEditor = _EditorDefaultSettings()
  1245.     else:
  1246.         _defaultSettingsEditor.w.select()
  1247.  
  1248. def resolvealiases(path):
  1249.     try:
  1250.         return macfs.ResolveAliasFile(path)[0].as_pathname()
  1251.     except (macfs.error, ValueError), (error, str):
  1252.         if error <> -120:
  1253.             raise
  1254.         dir, file = os.path.split(path)
  1255.         return os.path.join(resolvealiases(dir), file)
  1256.  
  1257. searchengine = SearchEngine()
  1258. tracebackwindow = Wtraceback.TraceBack()
  1259.